"""
    TorrentBrowser plugin for XBMC
    Copyright (C) 2011-2012 Markus Langenoja
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
    Functions
    ---------
    * loginOpen(url) - Download page which requires login
    * webOpen(url) - Download page which DOESN'T require login
    * buildCookie() - Initiate cookiejar
    * loginCookie(path-to-cookie) - Create a logged-in cookie
    * newCookie() - Removes cookie-file and creates new
    * loadCookie() - Tries to load the cookie file, runs checks to check
      if the cookies are still valid and not expired.
    * checkCookie(cookiejar) - Validates the cookiejar and sees if it is
      good for the site and not expired.
    * specialCookie(path-to-cookie) - Uses mechanize to fill form and
      download the proper cookies.
"""
import sys, os, time, urllib, re
import TBTools
from cookielib import LWPCookieJar
from urllib2 import build_opener, install_opener, HTTPCookieProcessor
from xbmc import translatePath

# This is the maximum number of retries which the script will try until failing.
max_tries = 7

class TBWeb(TBTools.TBTools):
    __deb__ = sys.modules[ "__main__" ].__deb__
    __plugin__ = sys.modules[ "__main__" ].__plugin__
    __settings__ = sys.modules[ "__main__" ].__settings__
    __info__ = sys.modules[ "__main__" ].__info__
    
    uname = __settings__.getSetting('username')
    upass = __settings__.getSetting('password')
    site = __settings__.getSetting('site')    
    
    def loginOpen(self, url, contentType=None):
        # Builds the path to the cookie
        self.__cookie__ = os.path.join(translatePath( "special://temp" ), "cookie.lwp")
        
        # Loads cookie
        self.loadCookie()
        
        # Open wanted url and obtain data
        src = self.__opener__.open(url)
        data = src.read()
        
        if contentType != None:
            contentType = str(src.info().getheader('Content-Type'))
        
        src.close()
            
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginOpen:: DONE for URL: %s' % (url)
            
        return data
    
    def webOpen(self, url):
        # Basically builds an opener to open a genral web url (TheMovieDB API e.g.)
        self.buildCookie()
        # Open and read url
        src = self.__opener__.open(url)
        data = src.read()
        src.close()
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'webOpen:: DONE for URL: %s' % (url)
        return data
        
    def buildCookie(self):
        # Create cookie jar and build & install the opener
        self.__cj__ = LWPCookieJar()
        self.__opener__ = build_opener(HTTPCookieProcessor(self.__cj__))
        install_opener(self.__opener__)
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'buildCookie:: DONE, cookie: %s' % (self.__cj__)
        return self.__cj__
    
    def loginCookie(self,__cookie__):
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: Logging in to site'
        # If the site requires Mechanize (RevTT) to login, use specialCookie (Mechanize)
        if self.__settings__.getSetting('site') == '7':
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: Site needs \'mechanize\' cookie: %s' % (self.__settings__.getSetting('site'))
            self.specialCookie(__cookie__)
            return
        
        # Build cookie
        self.buildCookie()
        
        # Extract site specific parameters
        upost = self.__info__['POSTUSER']
        ppost = self.__info__['POSTPASS']
        loginUrl = self.__info__['LOGINURL']
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: logging in via %s ' % (loginUrl)
            
        # Build the POST data from the login page and open the loginUrl together with POST data, thus logging in.
        # this section also checks the cookie if correctly logged in and gives the login procedure
        # a couple of chances to log in.
        goodCookie = False
        count = 1
        while not goodCookie:
            # Try logging in
            loginData = urllib.urlencode({upost:self.uname,ppost:self.upass})
            page = self.__opener__.open(loginUrl, loginData)
            
            # If the username/password combination is wrong, open settings
            regExp = self.__info__['FAILED']
            if re.search(regExp, page.read()):
                if self.__deb__:
                    print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: wrong username/password'
                self.showOK('Login Failed', 'Username/Password Wrong')
                self.__settings__.openSettings()
                os.remove(self.__cookie__)
                return self.loginCookie(__cookie__)
            page.close()
            
            # Check the cookie if logged in properly and check if the amount of retries is allowed
            goodCookie = self.checkCookie(self.__cj__)
            if count >= max_tries:
                if self.__deb__:
                    print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: login failed after %s retries' % (max_tries)
                self.showOK('LOGIN FAILED', 'The login procedure failed')
                return
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: try %s' % (count)
            count += 1
        
        # If the while clause is successful, save cookie
        self.__cj__.save(__cookie__, ignore_discard=True)
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loginCookie:: saving cookie %s\n to file %s' % (self.__cj__,__cookie__)
        
        # Returns the initiated opener containing "logged in" cookies    
        return self.__opener__
    
    def newCookie(self):
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'newCookie:: Creating new Cookies'
        try:
            os.remove(self.__cookie__)
        except: pass
        self.loginCookie(self.__cookie__)
        return
    
    def loadCookie(self):
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loadCookie:: Loading cookies'
        # Initiate the cookiejar and load the cookies saved to temp.
        self.buildCookie()
        try:
            self.__cj__.load(self.__cookie__,ignore_discard=True)
        except:
            self.newCookie()
        
        # Obtain cookie validation information unique for each site
        info = self.__info__.get('COOKIE')
        
        # Check if the cookie is for the correct site and if the cookies isn't expired
        if self.__cj__._cookies.has_key(info.get('domain')):
            # For every cookie contained in the cookiejar, check if the cookie is expired and
            # create new if any cookie is old.
            for cookie in self.__cj__:
                if cookie.expires:
                    if cookie.expires < time.time():
                        if self.__deb__:
                            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loadCookie:: Cookie is old(%s < %s), creating new' % (cookie.expires,time.time())
                        self.newCookie()
        else:
            self.newCookie()
        
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'loadCookie:: Cookie loaded successfully, cookie: %s' % (self.__cj__)
        return
    
    def checkCookie(self,cookiejar):
        # Obtain information to validate cookies
        info = self.__info__.get('COOKIE')
        # Check if the cookie is for the correct domain and if the verification cookie exists
        # which is chosen to be the password hash cookie for each site.
        if cookiejar._cookies.has_key(info.get('domain')):
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBWeb::' + 'checkCookie:: Cookie has the correct domain'
            # Check if the reference cookie exists and is not expired.
            if cookiejar._cookies.get(info.get('domain')).get('/').has_key(info.get('check')):
                if self.__deb__:
                    print self.__plugin__ + '::DEBUG::TBWeb::' + 'checkCookie:: Cookie has the correct check key'
                # Check if the cookie is expired
                checkCookie = cookiejar._cookies.get(info.get('domain')).get('/').get(info.get('check'))
                if checkCookie.expires > time.time():
                    if self.__deb__:
                        print self.__plugin__ + '::DEBUG::TBWeb::' + 'checkCookie:: Cookie is so fresh and so clean'
                    return True
                
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'checkCookie:: Cookie failed validation'
        # If the checks above fails, the default is False which will lead to a new retry.
        return False
            
    
    def specialCookie(self,__cookie__):          
        try:
            import resources.lib.mechanize as mechanize
        except:
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBWeb::' + 'specialCookie:: \'mechanize\' failed to load.'
            self.showOK('ERROR','Could not load Mechanize, make sure it is installed (easy_install mechanize)')
            return
        
        # Extract site specific parameters
        upost = self.__info__['POSTUSER']
        ppost = self.__info__['POSTPASS']
        loginUrl = self.__info__['LOGINURL']
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'specialCookie:: Logging in URL: %s' % (loginUrl)
            
        # Initiate cookiejar
        self.__cj__ = LWPCookieJar()
        
        # Initiate mechanize browser
        br = mechanize.Browser()
        br.set_cookiejar(self.__cj__)
        
        # Set browser parameters needed to log in on secure+ sites.
        br.set_handle_referer(True)
        br.set_handle_robots(False)
        br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')]
        
        # Open loginpage to start logging in and retry until either a good cookie is returned or 
        # the maximum amount of retries has been met.
        goodCookie = False
        count = 1
        while not goodCookie:
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBWeb::' + 'specialCookie:: Opening Site Url: %s' % (loginUrl)
            br.open(loginUrl)
            
            # Assumming the login form is the only on the site
            br.select_form(nr=0)
            
            # Fill form
            br.form[upost] = self.uname
            br.form[ppost] = self.upass
            br.submit()
            
            # Check the cookie if logged in correctly
            goodCookie = self.checkCookie(self.__cj__)
            
            if self.__deb__:
                print self.__plugin__ + '::DEBUG::TBWeb::' + 'specialCookie:: Login try %s' % (count)
                
            if count >= max_tries:
                # If the retry-count reaches the maximum retries, show a notification and return (which will produce an
                # error message)
                self.showOK('LOGIN FAILED', 'The login procedure failed after %s retries') % (max_tries)
                return
            
            # Increment the retry-count
            count += 1
        
        if self.__deb__:
            print self.__plugin__ + '::DEBUG::TBWeb::' + 'specialCookie::  Saving Cookie to %s' % (__cookie__)
            
        # Now with login completed, save the cookie so we dont have to repeat this :)
        self.__cj__.save(__cookie__, ignore_discard=True)
                
        # Install the cookie into opener
        self.__opener__ = build_opener(HTTPCookieProcessor(self.__cj__))
        install_opener(self.__opener__)
        
        # Returns the initiated opener containing "logged in" cookies    
        return self.__opener__